package org.simpleframework.mvc.processor.impl;

import lombok.extern.slf4j.Slf4j;
import org.simpleframework.mvc.DispatcherServlet;
import org.simpleframework.mvc.RequestProcessorChain;
import org.simpleframework.mvc.processor.RequestProcessor;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;

/**
 * 静态资源请求处理器:将静态资源转发给指定servlet进行处理.包括但不限于图片、css、以及js文件等 - DefaultServlet
 * <p>
 * 在tomcat中真正管理Servlet容器的是Context容器,一个Context对应一个web工程,Context代表servlet的上下文.具备servlet运行的基本环境,管理其中的
 * servlet实例.,servlet实例在Context中以Wrapper形式存在的.一个Wrapper装有一个Servlet实例,他主要负责管理一个Servlet.包装其装载初始化,执行以及资源回收等,Wrapper是
 * 最底层的容器,所以为了将请求转发给Servlet进行处理,我们需要从从Context中获取到对应的Wrapper实例,
 * Context如何获取到-- DisPatchServlet中进行获取--继承了HTTPServlet,具有getServletContext的功能,
 * <p>
 * 但是在tomcat中Wrapper并不是叫做Wrapper,而是叫做RequestDispatcher,可能是因为Wrapper需要将请求派发给Servlet进行处理的原因.
 *
 * @author: Oliver
 * @time: 2020/12/28/23:01
 */
@Slf4j
public class StaticResourceRequestProcessor implements RequestProcessor {

    public static final String STATIC = "/static";
    public static final String DEFAULT_SERVLET = "default";
    //tomcat默认请求派发器RequestDispatcher的名称
    private RequestDispatcher defaultServlet;

    public StaticResourceRequestProcessor(ServletContext servletContext) {
        defaultServlet = servletContext.getNamedDispatcher(DEFAULT_SERVLET);
        if (this.defaultServlet == null) {
            throw new RuntimeException("There is no default tomcat servlet");
        }
        log.info("The default servlet for static resource is {}", DEFAULT_SERVLET);
    }

    /**
     * 规定静态资源放在 static目录下 于是进行解析路径为static开头,则为静态资源访问
     *
     * @param chain 调用链,用于结果处理参数的组装,以及处理时必要的参数信息传递
     * @return
     * @throws Exception
     */
    @Override
    public boolean process(RequestProcessorChain chain) throws Exception {
        String path = chain.getMethodPath();
        if (isStatic(path)) {
            // 使用tomcat默认servlet进行转发到静态资源上,进行放行处理.
            defaultServlet.forward(chain.getRequest(), chain.getResponse());
            return false;
        }
        return true;
    }

    /**
     * 判断资源是否为static资源
     *
     * @param path 访问路径
     * @return boolean
     */
    private boolean isStatic(String path) {
        return path.startsWith(STATIC);
    }
}
